home *** CD-ROM | disk | FTP | other *** search
/ isnet Internet / Isnet Internet CD.iso / prog / hiz / 09 / 09.exe / adynware.exe / perl / lib / decorate.pm < prev    next >
Encoding:
Text File  |  2000-05-01  |  39.5 KB  |  1,176 lines

  1. use strict;
  2. use diagnostics;
  3. package Decorate;
  4. use Fcntl;
  5. use IO::File;
  6. use adynware::web_site;
  7. use adynware::utility;
  8. use adynware::utility_file;
  9. use adynware::unique_scripts;
  10.  
  11.  
  12.  
  13.  
  14. my $__color = "red";
  15. sub setColor { ($__color) = @_; }
  16.  
  17. my $__documentIDGenerator = 1;
  18.  
  19. my $__enabled = 1;
  20. sub setEnabled { ($__enabled) = @_; }
  21.  
  22. my $__expression = "<FONT color=$__color><B><SUP>%d</SUP></B></FONT>";
  23. sub setDefaultSuperscriptExpression { $__expression = "<FONT color=$__color><B><SUP>%d</SUP></B></FONT>"; }
  24. sub setSuperscriptExpression { ($__expression) = @_; }
  25. setDefaultSuperscriptExpression();
  26.  
  27.  
  28. my $__listFormsFirst = 0;
  29. sub listFormsFirst { $__listFormsFirst = 1; }
  30.  
  31. my $decorate__enabledJavaScriptHeader = "";
  32. my $__unique = 0;
  33. sub setUnique { ($__unique) = @_;}
  34.  
  35. my $__version = "";
  36. sub setVersion { ($__version) = @_; }
  37.  
  38.  
  39.  
  40.  
  41. my $WINDOW_GOTO   = "wk_window_goto(null,";
  42. my $WINDOW_CREATE = "wk_window_goto(";
  43.  
  44. my $decorate__disabledJavaScriptHeader =<<'EOS';
  45. <script language="JavaScript">
  46.  
  47. var c_char_w = 119;
  48. var wk_chained_key_handler = null;
  49.  
  50. function wk_key_handler(e) 
  51. {
  52.         if (e.target.type) return true;
  53.         else if (e.which==c_char_w)
  54.         {
  55.                 if (confirm("Enable Web Keyboard processing?")) 
  56.                 {
  57.                         window.open("http://__adynware__/perl/" + escape('Decorate::setEnabled(1)'), "tmp", "width=1,height=1");
  58.                         setTimeout("location.reload(true)", 500);
  59.                 } 
  60.                 return false;
  61.         }
  62.         if (wk_chained_key_handler) return wk_chained_key_handler();
  63.         return true;
  64. function wk_frame_onLoad()
  65. {
  66.         if (document.onKeyPress != wk_key_handler)
  67.         {
  68.                 wk_chained_key_handler = document.onKeyPress;
  69.                 document.onKeyPress = wk_key_handler;
  70.         } 
  71. }
  72. document.captureEvents(Event.KEYPRESS);
  73. document.onKeyPress = wk_key_handler;
  74. EOS
  75.  
  76. $decorate__enabledJavaScriptHeader =<<'EOS';
  77. <script language="JavaScript">
  78. var WINDOW_GOTO;
  79. var WINDOW_CREATE;
  80. var wk_action = new Array();
  81. var wk_chained_key_handler = null;
  82. var wk_chained_onerror = null;
  83. var wk_data = new Array();
  84. var wk_documentID;
  85. var wk_index = 0;
  86. var wk_itemCount = 0;
  87. var wk_loadComplete = false;
  88. var wk_minimumIndex = 0;
  89.  
  90. var c_control_e = 5;
  91. var c_control_j = 10;
  92. var c_control_k = 11;
  93. var c_control_l = 12;
  94. var c_control_t = 20;
  95. var c_control_y = 25;
  96.  
  97. var c_char_c = 99;
  98. var c_char_n = 110;
  99. var c_char_w = 119;
  100. var c_char_0 = 48;
  101. var c_char_9 = 57;
  102.  
  103. function wk_key_handler(e) 
  104. {
  105.         //defaultStatus = "got " + e.which; return true;
  106.         if (e.which==c_control_j)
  107.         {
  108.                 wk_frame_goto_next_interesting_leaf(1);
  109.                 return false;
  110.         }
  111.         if (e.which==c_control_l)
  112.         {
  113.                 wk_frame_goto_next_interesting_leaf(-1);
  114.                 return false;
  115.         }
  116.                                     
  117.         if (e.target.type) 
  118.         {
  119.                 if (e.which==c_control_e)
  120.                 {
  121.                         e.target.blur();
  122.                         window.defaultStatus = "Enter jump index:";
  123.                         return false;
  124.                 }
  125.                 return true;
  126.         }
  127.         if (c_char_0 <= e.which && e.which <= c_char_9)
  128.         {
  129.                 if (wk_index==0 && e.which==c_char_0)
  130.                 {
  131.                         window.defaultStatus = wk_data[0];
  132.                 }
  133.                 wk_index = (wk_index * 10) + e.which - c_char_0;
  134.                 var w = wk_find_item(wk_index);
  135.                 if (w) 
  136.                 {
  137.                         w.focus();
  138.                 }
  139.                 else
  140.                 {
  141.                         wk_index = e.which - c_char_0;
  142.                         w = wk_find_item(wk_index);
  143.                         if (w) 
  144.                         {
  145.                                 w.focus();
  146.                         }
  147.                         else w = window;
  148.                 }
  149.                 w.wk_index = wk_index;
  150.                 wk_link_show(w, wk_index);
  151.                 return false;
  152.         }
  153.         else if (e.which==c_char_c && 0 < wk_index && wk_index < wk_data.length)
  154.         {
  155.                 window.open("http://__adynware__/setClipboard/" + escape(wk_data[wk_index]), "tmp", "width=1,height=1");
  156.         }
  157.         else if (e.which==c_char_n && 0 < wk_index && wk_index < wk_data.length)
  158.         {
  159.                 if (wk_action[wk_index].indexOf(WINDOW_CREATE) >= 0)
  160.                 {
  161.                         window.open(wk_data[wk_index]);
  162.                 }
  163.                 else
  164.                 {
  165.                         defaultStatus = wk_data[wk_index] + " is not a window";
  166.                 }
  167.         }
  168.         else if (e.which==c_char_w)
  169.         {
  170.                 if (confirm("Disable Web Keyboard until you enter 'w' in the background?")) 
  171.                 {
  172.                         window.open("http://__adynware__/perl/" + escape('Decorate::setEnabled(0)'), "tmp", "width=1,height=1");
  173.                         setTimeout("location.reload(true)", 500);
  174.                 } 
  175.                 return false;
  176.         }
  177.         else 
  178.         {
  179.                 var tmpIndex = wk_index;
  180.                 wk_index = 0;
  181.                 if (e.which==13)
  182.                 {
  183.                         wk_link_goto(tmpIndex);
  184.                         return false;
  185.                 }
  186.         }
  187.         var notHandled = true;
  188.         if (wk_chained_key_handler)
  189.         {
  190.                 notHandled = wk_chained_key_handler();
  191.         }
  192.         if (notHandled) defaultStatus = "";
  193.         return notHandled;
  194. }
  195. function wk_get_field(originalFormIndex, originalFieldIndex, fieldName)
  196. {
  197.         var fieldIndex = originalFieldIndex;
  198.         for (var formIndex = originalFormIndex; formIndex < document.forms.length; formIndex++)
  199.         {
  200.                 var elements = document.forms[formIndex].elements;
  201.                 while (fieldIndex < elements.length)
  202.                 {
  203.                         //alert('Examining form ' + formIndex + ': field ' + fieldIndex + ': ' + elements[fieldIndex].name);
  204.                         if (elements[fieldIndex].name==fieldName) return elements[fieldIndex];
  205.                         fieldIndex++;
  206.                 }
  207.                 fieldIndex = 0;
  208.         }
  209.         alert("Web Keyboard: could not find field " + fieldName + " in form " + originalFormIndex);
  210.         return document.forms[originalFormIndex].elements[originalFieldIndex];
  211. function wk_get_link(href)
  212. {
  213.         for (var j=0; j < document.links.length; j++)
  214.         {
  215.                 if (document.links[j].href==href) return document.links[j];
  216.         }
  217.         alert("Web Keyboard: could not find a link with href " + href);
  218.         return null;
  219. function wk_find_item(n)
  220. {
  221.         if (n < wk_data.length && wk_data[n]) return self;
  222.         
  223.         var maxScript = wk_data.length - 1;
  224.         var w = wk_frame_get_next_leaf(self, 1);
  225.         for (var j = 0; w!=self && j < 20; j++)
  226.         {
  227.                 if (w.wk_data)
  228.                 {
  229.                         if ((n < w.wk_data.length) && w.wk_data[n]) return w;
  230.                 
  231.                         if (maxScript < w.wk_data.length - 1) maxScript = w.wk_data.length - 1;
  232.                 }
  233.                 w = wk_frame_get_next_leaf(w, 1);
  234.         }
  235.         if (n > maxScript) 
  236.         {
  237.                 return null;
  238.         } 
  239.         return self;
  240. }
  241. function wk_click_first_checkbox(box)
  242. {
  243.         if (eval(box + "[1]!=null"))
  244.         {
  245.                 eval(box + "[0].click()");
  246.         }
  247.         else
  248.         {
  249.                 eval(box + ".click()");
  250.         }
  251. }
  252.     
  253. function wk_link_goto(index) 
  254. {
  255.         if (index==0)
  256.         {
  257.                 defaultStatus = "no jump index specified";
  258.         }
  259.         else if (0 < index && index < wk_data.length && wk_data[index])
  260.         {
  261.                 if (wk_action[index] && wk_action[index]!="JavaScript")
  262.                 {
  263.                         var xx = "";
  264.                         var s = wk_action[index] +  "wk_data[" + index + "])";
  265.                         //alert('evaluation 1:'  + s);
  266.                         eval(s);
  267.                         //alert('evaluation 2:'  + xx);
  268.                         eval(xx);
  269.                 }
  270.                 else
  271.                 {
  272.                         //alert(' evaluating ' + wk_data[index]);
  273.                         eval(wk_data[index]);
  274.                 }
  275.         }
  276. }
  277.  
  278. function wk_link_show(w,index)
  279. {
  280.         if (!w.wk_data) return;
  281.         
  282.         var s = "";
  283.         if (0 > index || index >= w.wk_data.length) return;
  284.         else if (0==index) s = w.wk_data[0];
  285.         else 
  286.         {    
  287.                 s += index + ": ";
  288.                 if (w.wk_action[index] && ((w.wk_action[index].indexOf(WINDOW_GOTO) >= 0) || (w.wk_action[index].indexOf(WINDOW_CREATE) >= 0) || (w.wk_action[index] == "JavaScript")))
  289.                 {
  290.                         s += w.wk_data[index];
  291.                 }
  292.                 else if (w.wk_data[index] != null)
  293.                 {
  294.                         s += "form field";
  295.                 }
  296.                 else
  297.                 {
  298.                         s += "-";
  299.                 }
  300.         }
  301.         w.defaultStatus = defaultStatus = s;
  302. }
  303.  
  304. function wk_frame_dive(w, direction)
  305. {
  306.         while (w.frames.length > 0)
  307.         {
  308.                 if (direction==-1)
  309.                 {
  310.                         w=w.frames[0];
  311.                 }
  312.                 else
  313.                 {
  314.                         w=w.frames[w.frames.length -1];
  315.                 }
  316.         }
  317.         return w;
  318. }
  319.  
  320. function wk_get_frame_name(w)
  321. {
  322.         if(w==w.top) return "window.top";
  323.         var parent = w.parent;
  324.         for (var j = 0; j < parent.frames.length; j++)
  325.         {
  326.                 if(parent.frames[j]==w) return wk_get_frame_name(parent) + ".frames[" + j + "]";
  327.         }
  328.         alert(' wk_get_frame_name could not resolve a frame');
  329.         return "";
  330. }
  331.  
  332. var wk_flashing = false;
  333. var wk_preventFlash = 0;
  334. function wk_flash(w)
  335. {
  336.         if (wk_preventFlash > 0)
  337.         {
  338.                 wk_preventFlash--;
  339.                 return;
  340.         }
  341.         if (wk_flashing || (w==window.top)) return;
  342.         wk_flashing = true;
  343.                         
  344.         var x = wk_get_frame_name(w) + ".document.bgColor = '" + w.document.bgColor + "'; wk_flashing = false";
  345.         w.setTimeout(x, 300);
  346.         if(w.document.bgColor=="#808080") w.document.bgColor = "black";
  347.         else                              w.document.bgColor = "gray";
  348. }
  349.  
  350. function wk_frame_get_index(w)
  351. {
  352.         if ((w.self==window.top) || (w.parent.frames.length==1))
  353.         {
  354.                 return 0;
  355.         }
  356.         var j;
  357.         for (j = 0; j < w.parent.frames.length; j++)
  358.         {
  359.                 if (w.parent.frames[j]==w)
  360.                 {
  361.                         return j;
  362.                 }
  363.         }
  364.         alert("could not find current window in w.parent.frames");
  365.         return 0;
  366. }
  367.  
  368. function wk_frame_get_sibling(w, increment)
  369. {
  370.         if (w==window.top)
  371.         {
  372.                 return null;
  373.         }
  374.         var index = wk_frame_get_index(w);
  375.         index += increment;
  376.         if ((index < 0) || (index >= w.parent.frames.length))
  377.         {
  378.                 return null;
  379.         }
  380.         return w.parent.frames[index];
  381. }
  382.  
  383. function wk_frame_get_next_leaf(w, increment)
  384. {
  385.         while (w!=window.top)
  386.         {
  387.             var sibling = wk_frame_get_sibling(w, increment);
  388.             if(!sibling) w = w.parent;
  389.             else
  390.             {
  391.                 w = sibling;
  392.                 break;
  393.             } 
  394.         }
  395.         return wk_frame_dive(w, -increment);
  396. }
  397. function wk_frame_goto_next_interesting_leaf(increment)
  398. {
  399.         var firstNeighbor = wk_frame_get_next_leaf(self, increment);
  400.         var w = firstNeighbor;
  401.         var next = w;
  402.         for (var j = 0; !w.wk_itemCount && j < 20; j++)
  403.         {
  404.                 w = wk_frame_get_next_leaf(w, increment);
  405.                                                                                 
  406.                 if (w==firstNeighbor || w==self) 
  407.                 {
  408.                         next = firstNeighbor;
  409.                         break;
  410.                 } 
  411.                 next = w;
  412.         }
  413.         next.focus();
  414.         next.wk_index = 0;
  415.         wk_flash(next);
  416. }
  417. function wk_window_find(name, w)
  418. {
  419.         if (!w) return null;
  420.         if (w.name==name) return w;
  421.         for (var j = 0; j<w.frames.length; j++)
  422.         {
  423.                 var hit = wk_window_find(name, w.frames[j]);
  424.                 if (hit) return hit;
  425.         }
  426.         return null;
  427. }
  428. function wk_window_goto(windowName, link)
  429. {
  430.         var targetWindow;
  431.         if (windowName) targetWindow = wk_window_find(windowName, self.top);
  432.         else            targetWindow = self;
  433.                                
  434.         //alert("window goto(" + windowName + "," + link + "):" + targetWindow);
  435.         //if (targetWindow)
  436.         //{
  437.         //alert("targetWindow.top.wk_documentID=" + targetWindow.top.wk_documentID + "\ntargetWindow.wk_documentID=" + targetWindow.wk_documentID);
  438.         //}
  439.                 
  440.         if (targetWindow
  441.         && targetWindow.top.wk_documentID
  442.         && targetWindow.wk_documentID
  443.         && link.charAt(0) != '#'
  444.         && link.indexOf("javascript:") == -1
  445.         && (targetWindow.top.wk_documentID != targetWindow.wk_documentID))
  446.         {
  447.                 var s = "$redirectTarget='" + link + "';unique_scripts::replaceFrame(" + targetWindow.top.wk_documentID + "," + targetWindow.wk_documentID + ", '" + link  + "');";
  448.                 s = "http://__adynware__/perl/" + escape(s);
  449.                 if (windowName)
  450.                 {
  451.                         open(s, windowName);
  452.                 }
  453.                 else
  454.                 {
  455.                         location = s;        
  456.                 }
  457.         }
  458.         else
  459.         {
  460.                 if (windowName)
  461.                 {
  462.                         open(link, windowName);        
  463.                 }
  464.                 else
  465.                 {
  466.                         window.location = link;        
  467.                 } 
  468.         } 
  469. }
  470. function wk_frame_onLoad()
  471. {
  472.         if (onerror != wk_onerror)
  473.         {
  474.                 wk_chained_onerror = onerror;
  475.                 onerror = wk_onerror;
  476.         } 
  477.         if (document.onKeyPress != wk_key_handler)
  478.         {
  479.                 wk_chained_key_handler = document.onKeyPress;
  480.                 document.onKeyPress = wk_key_handler;
  481.         }
  482.         wk_loadComplete = true;
  483. }
  484. function wk_onerror(message, URL, line)
  485. {
  486.         if (message.indexOf("access disallowed from scripts")==-1) 
  487.         {
  488.                 if (wk_chained_onerror) return wk_chained_onerror();
  489.                 return false;
  490.         }
  491.         setTimeout("defaultStatus = ''", 2000);
  492.         defaultStatus = "Web Keyboard: JavaScript prevents frames from different domains from communicating";
  493.         return true;
  494.  
  495. document.captureEvents(Event.KEYPRESS);
  496. document.onKeyPress = wk_key_handler;
  497. onerror = wk_onerror;
  498. EOS
  499.  
  500. $decorate__enabledJavaScriptHeader .= "\nWINDOW_GOTO = '$WINDOW_GOTO';\nWINDOW_CREATE = '$WINDOW_CREATE';\n";
  501.  
  502.  
  503. sub SuperScript
  504. {
  505.         my($self, $isLink, $data, $action) = @_;
  506.         $self->{"itemCount"}++;
  507.                         
  508.         my $index;
  509.         if (defined $self->{"unique"})
  510.         {
  511.                 my $x = $self->{"unique"};
  512.                 my $documentID = $self->{"documentID"};
  513.                 $index = $$x->getIndex($documentID, $isLink);
  514.                 $self->{"index"} = $index + 1;     # disaster insurance: keep in sync
  515.         }
  516.         elsif ($isLink or !defined $self->{"formFieldIndex"} or (25 < $self->{"formFieldIndex"}))
  517.         {
  518.                 $index = $self->{"index"}++;
  519.         }
  520.         else
  521.         {
  522.                 $index = $self->{"formFieldIndex"}++;
  523.         }
  524.                 
  525.         if (!defined $self->{"firstItemDone"})
  526.         {
  527.                 $self->{"firstItemDone"} = 1;
  528.                 $self->{"pendingJavaScript"} .= "wk_minimumIndex=$index;\n";
  529.         } 
  530.  
  531.         $data =~ s/\000//g; # remove garbage which HTML allows but JavaScript doesn't
  532.         if (!$isLink)
  533.         {
  534.                 $data = "'$data'";
  535.                 $action = "\"$action\"" if defined $action;
  536.         }
  537.         $self->{"pendingJavaScript"} .= "wk_data[$index]=" . $data . ";\n";
  538.         if (defined $action)
  539.         {
  540.                 $self->{"pendingJavaScript"} .= "wk_action" . "[$index]=$action;\n";
  541.         }
  542.         #print "decorate::Super script $index: $data\n";
  543.         return sprintf $__expression, $index;
  544. }
  545.  
  546. sub Init
  547. {
  548.         my($self, $target, $status) = @_;
  549.         if (defined $target)
  550.         {
  551.                 $self->{"base"} = utility_file::dirname($target) . "/";
  552.         }
  553.         else
  554.         {
  555.                 $self->{"base"} = "";
  556.         }
  557.         utility::Log("decorate::Init($self, $target, $status)" . $self->{"base"});
  558.                         
  559.         $self->{"allJavaScript"} = "";
  560.         $self->{"documentID"} = $__documentIDGenerator++;    
  561.         $self->{"enabled"} = 1;
  562.         $self->{"fieldIndex"} = 0;    # place to keep track of form field index 
  563.         $self->{"formIndex"} = -1;    # place to keep track of form index 
  564.         $self->{"hasScriptContent"} = 0;    # is there JavaScript code in the document already?
  565.         $self->{"headerSeen"} = 0;
  566.                 
  567.         if ($__listFormsFirst)
  568.         {
  569.                 $self->{"index"} = 26;        # counter for generating superscripts for links
  570.                 $self->{"formFieldIndex"} = 1;    # counter for generating superscripts for form fields
  571.         }
  572.         else
  573.         {
  574.                 $self->{"index"} = 1;        # counter for generating superscripts for all items, unless unique
  575.         }
  576.         
  577.         $self->{"inputGroupIndices"} = {};    # place to keep track of radio button indices
  578.         $self->{"inForm"} = 0;        # are we in a form?
  579.         $self->{"inScript"} = 0;    # are we within a <script...</script> block?  If yes, then be careful.
  580.         $self->{"inComment"} = 0;    # are we within a <--...!-> HTML comment block?  If yes, then ignore fields.
  581.         $self->{"itemCount"} = 0;
  582.         $self->{"pendingJavaScript"} = "wk_documentID = " . $self->{"documentID"} . ";\n";
  583.         $self->{"nameGenerationIndex"} = 0;
  584.         $self->{"safe"} = 1;        # is it safe to insert JavaScript?
  585.         $self->{"slicedItem"} = "";    # holding area for link fragment which crosses the chunk boundary
  586.         $self->{"status"} = "Processing...";
  587.         $self->{"target"} = $target;
  588.         $self->{"unique"} = unique_scripts::findFrameGroup($target, ($status!=302));
  589.         return "";
  590. }                
  591.  
  592. sub Cleanup
  593. {
  594.         my($self) = @_;
  595.         my $string = $self->{"slicedItem"};
  596.         
  597.         return $string unless $self->{"enabled"} and $self->{"headerSeen"};
  598.         
  599.         return "$string\n<script language=\"JavaScript\">\nwk_frame_onLoad();\n</script>\n" unless $__enabled;
  600.                 
  601.                                 
  602.         $self->{"status"} = "Done";
  603.         
  604.         $string .= $self->GetPendingJavaScript(1, "wk_frame_onLoad();", 1);
  605.         
  606.         return $string;
  607. }
  608.  
  609. sub DoLink
  610. {
  611.         my($self, $link) = @_;
  612.         my $linkDestination;
  613.         if ($link =~ m{\bhref\s*=\s*("\s*[^"]+\s*")}i)
  614.         {
  615.                 $linkDestination = $1;
  616.         }
  617.         elsif ($link =~ m{\bhref\s*=\s*('\s*[^']+\S\s*')}i)
  618.         {
  619.                 $linkDestination = $1;
  620.         }
  621.         elsif ($link =~ m{\bhref\s*=\s*([^'"\s>]+)}i)
  622.         {
  623.                 $linkDestination = qq("$1");
  624.         }
  625.         else
  626.         {
  627.                 return ""; # anchor
  628.         }
  629.                         
  630.         my $JavaScript = undef;
  631.         if ($link =~ m{\bonclick\s*=\s*("\s*[^"]+\s*")}i)
  632.         {
  633.                 $JavaScript = $1;
  634.         }
  635.         if ($link =~ m{\bonclick\s*=\s*('\s*[^']+\s*')}i)
  636.         {
  637.                 $JavaScript = $1;
  638.         }
  639.         if (!defined $JavaScript)
  640.         {
  641.                 $JavaScript = "";
  642.         }
  643.         else
  644.         {
  645.                 my $cookedLinkDestination = $linkDestination;
  646.                 #$cookedLinkDestination =~ s/(['"])/\\$1/g;
  647.                 $JavaScript =~ s/\n/ /g;
  648.                 $JavaScript =~ s/return\s+true\s*(['"])\s*$/$1/;
  649.                 $JavaScript =~ s/this/wk_get_link($cookedLinkDestination)/g;
  650.                 $JavaScript =~ s/(['"])/\\$1/g;
  651.                 $JavaScript = "'xx=' + \"$JavaScript\" + ';' + ";
  652.         }
  653.                                 
  654.         return "" if $link =~ /\bismap\b/i;         # no support for image maps
  655.                                                 
  656.         $linkDestination =~ s/[\015\n]//g;         # remove ^Ms
  657.                                                 
  658.         $linkDestination =~ s/\bjavascript:/javascript:/i; # assures lowercase
  659.                 
  660.         my $mark = "";
  661.         if ($linkDestination =~ s/^(['"])(.*)['"]$/$2/)
  662.         {
  663.                 # removed trailing and leading quotes
  664.                 $mark = $1;
  665.         }
  666.                                                                                                 
  667.         $linkDestination = $mark . web_site::makeAbsolute($linkDestination, $self->{"base"}, $self->{"target"}) . $mark;
  668.                                                                         
  669.         my $action;
  670.         my $target = "";
  671.         if ($link =~ m{\btarget\s*=\s*['"]?(\w+)}i )
  672.         {
  673.                 $target = $1;
  674.         }
  675.         elsif (defined $self->{"window_target"})
  676.         {
  677.                 $target = $self->{"window_target"};
  678.         }
  679.                                         
  680.         if ($target)
  681.         {
  682.                 $action = $WINDOW_CREATE . "'$target', ";
  683.         }
  684.         else
  685.         {
  686.                 $action = $WINDOW_GOTO;
  687.         }
  688.         $action = "\"$action\""; 
  689.         return $self->SuperScript(1, $linkDestination, $JavaScript . $action);
  690. }
  691.  
  692. sub ProcessBaseStatements
  693. {
  694.         my($self, $string) = @_;
  695.         my $baseStatements = "";
  696.                 
  697.         # capture trailing comment limit in the following regexp, so we can tell what base statements were really commented out
  698.         while ($string =~ /<base\b(.*?>)\s*(-->)?/gis)
  699.         {
  700.                 $baseStatements .= $1 unless $2;
  701.         }
  702.         if ($baseStatements)
  703.         {
  704.                 my $statement = $baseStatements;
  705.                                                                                                         
  706.                 if ($statement =~ s{.*\bhref\s*=\s*}{}i)
  707.                 {
  708.                         if ($statement =~ m{^'([^']*?)'}gi
  709.                         or  $statement =~ m{^"([^"]*?)"}gi
  710.                         or  $statement =~ m{^([^\s'">]+)}gi)
  711.                         {
  712.                                 my $base = $self->{"base"};
  713.                                 if (!$base)
  714.                                 {
  715.                                         $base = $1;
  716.                                 }
  717.                                 else
  718.                                 {
  719.                                         $base = web_site::makeAbsolute($1, $base, undef);
  720.                                 }   
  721.                                 $self->{"base"} = utility_file::dirname($base) . "/";
  722.                         }
  723.                         $statement = $baseStatements;
  724.                 }
  725.                 if ($statement =~ s{.*\btarget\s*=\s*}{}i)
  726.                 {
  727.                         if ($statement =~ m{^'([^']*?)'}gi
  728.                         or  $statement =~ m{^"([^"]*?)"}gi
  729.                         or  $statement =~ m{^([^\s'">]+)}gi)
  730.                         {
  731.                                 $self->{"window_target"} = $1;
  732.                         }
  733.                 }
  734.         }
  735. }
  736.  
  737.  
  738. sub DoLinks
  739. {
  740.         my($self, $string) = @_;
  741.                         
  742.         # ignore links with no associated text (e.g., <a  href="http://alpha.cmpexpress.com/store/htmlos/27127" ></a>)
  743.         $string =~ s
  744.         {
  745.                 <\s*a\b([^>]*>\s*)<\s*/\s*a\s*>
  746.         }{"<_a" . $1 . "</_a>"}egisx;
  747.                                 
  748.         $string =~ s
  749.         {
  750.                 <\s*a\b([^<]*?)<\s*/\s*a\s*>
  751.         }{"<_a" . $1 . "</_a>" . $self->DoLink($1)}egisx;
  752.                                 
  753.         # process links which are terminated with /a, but have nested HTML declarations
  754.         $string =~ s
  755.         {
  756.                 <\s*a\b(.*?)<\s*/a\s*>
  757.         }{"<_a" . $1 . "</_a>" . $self->DoLink($1)}egisx;
  758.         
  759.         # process links which are terminated with /td
  760.         $string =~ s
  761.         {
  762.                 <\s*a\b(.*?)<\s*/td\s*>
  763.         }{"<_a" . $1 . $self->DoLink($1) . "</td>"}egisx;
  764.                                                                                  
  765.         # process links which are not terminated with /a, or which have nested font directives
  766.         #$string =~ s
  767.         #{
  768.         #<\s*a\b(.*?)<(.*?)>
  769.         #}{"<_a" . $1 . "</_a>" . $self->DoLink($1) . "<$2>"}egisx;
  770.                                                                                  
  771.                                
  772.         if ($string =~ s/(<\s*a\b.*$)//is)
  773.         {
  774.                 my $addition = $1;
  775.                 if ($addition =~ m{</?_a})
  776.                 {
  777.                         utility::Log("confused by malformed HTML: mismatched <a> and </a> seen");
  778.                         $string .= $addition;    # put it back
  779.                 }
  780.                 else
  781.                 {
  782.                         if ($self->{"slicedItem"})
  783.                         {
  784.                                 utility::Log("a: already: slice:" . $self->{"slicedItem"});
  785.                                 $self->{"slicedItem"} = $addition . $self->{"slicedItem"};
  786.                         }
  787.                         else
  788.                         {
  789.                                 $self->{"slicedItem"} = $addition;
  790.                         }
  791.                 }
  792.         }
  793.                                                                         
  794.         $string =~ s/<_a/<a/g;
  795.         $string =~ s{</_a}{</a}g;
  796.         return $string;
  797. }                                
  798.         
  799. sub Chunk
  800. {
  801.         my($self, $stringR) = @_;
  802.                                                
  803.         if ($self->{"slicedItem"})
  804.         {
  805.                 utility::Log("chunk: slice:" . $self->{"slicedItem"});
  806.                 $$stringR = $self->{"slicedItem"} . $$stringR;
  807.                 $self->{"slicedItem"} = "";
  808.         }
  809.         if ($$stringR =~ s/(<[^<>]*$)//is) # grab sliced tag from the end
  810.         {
  811.                 $self->{"slicedItem"} = $1;
  812.         }
  813.                                 
  814.         #$$stringR =~ s/(<script[^>]*>)\s*<!--[^\n]*/$1 /gis; 
  815.         #$$stringR =~ s{-->\s*(</script)}{ $1}gis; 
  816.         #$$stringR =~ s/<!--.*?-->//gs; 
  817.                                                                         
  818.         $self->ProcessBaseStatements($$stringR);
  819.                                                         
  820.         my $headerPreviouslyInserted = $self->{"headerSeen"};
  821.         if (!$headerPreviouslyInserted)
  822.         {
  823.                 if ($$stringR =~ /wk_key_handler/)
  824.                 {
  825.                         utility::Log($self->{"target"} . " contents already processed by Web Keyboard");
  826.                         $self->{"enabled"} = 0; 
  827.                 }
  828.                 elsif ($$stringR !~ /^\s*</s and $$stringR !~ /^\s*$/s)
  829.                 {
  830.                         utility::Log($self->{"target"} . " contents do not look like HTML.  Web Keyboard will not process this file");
  831.                         $self->{"enabled"} = 0; 
  832.                 }
  833.                 else
  834.                 {
  835.                         my $header = $__enabled ? $decorate__enabledJavaScriptHeader : $decorate__disabledJavaScriptHeader;
  836.                                                 
  837.                         $header .= $self->{"pendingJavaScript"} . "\n";
  838.                         $self->{"pendingJavaScript"} = "";
  839.                                                 
  840.                         $header .= "</script>\n";
  841.                         if ($$stringR !~ s{<HEAD>}{<HEAD>$header}i)
  842.                         {
  843.                                 $$stringR = $header . $$stringR;
  844.                         }
  845.                         $self->{"headerSeen"} = 1;
  846.                 }
  847.         }
  848.         return unless $__enabled and $self->{"enabled"};
  849.         if ($$stringR =~ m{\bdocument\.write}i)
  850.         {
  851.                 utility::Log("saw document.write calls");
  852.                                                                                                 
  853.                 $self->{"safe"} = 0;
  854.         }
  855.         my $inScript = $self->{"inScript"};
  856.         #utility::Log("Chunk processing entrance: in script: $inScript");
  857.                                                                                                                                         
  858.         if (!$self->{"hasScriptContent"} and $$stringR =~ m{<\s*script\b}i)
  859.         {
  860.                 $self->{"hasScriptContent"} = 1;
  861.                 $self->{"safe"} = 0;
  862.         }
  863.                                                                                         
  864.         my @processedChunks = ();
  865.         my $generationIndex = 0;
  866.         $$stringR =~ s{</script>(.*?)<script}{$processedChunks[$generationIndex] = $self->DoChunk($1, "/script to script"), "<s__" . $generationIndex++ . "__t>"}egis;
  867.                                                                                                         
  868.         if ($inScript)
  869.         {
  870.                 if ($$stringR =~ s{</script(.*)}{"</s____t" . $self->DoChunk($1, "in:/script on")}egis)
  871.                 {
  872.                         $self->{"inScript"} = 0;
  873.                 }
  874.         }
  875.         else
  876.         {
  877.                 if ($$stringR =~ s{^(.*?)<script}{$self->DoChunk($1, "out: to script") . "<s____t"}egis)
  878.                 {
  879.                         if ($$stringR =~ s{</script>(.*)}{"</s____t>" . $self->DoChunk($1, "out:/script on")}egis)
  880.                         {
  881.                                 $self->{"inScript"} = 0;
  882.                         }
  883.                         else
  884.                         {
  885.                                 $self->{"inScript"} = 1;
  886.                         }
  887.                 }
  888.                 else
  889.                 {
  890.                         $$stringR = $self->DoChunk($$stringR, "out: all");
  891.                 } 
  892.         }
  893.         $$stringR =~ s/\bs____t\b/script/g;
  894.         $$stringR =~ s{<s__(\d+)__t>}{"</script>" . $processedChunks[$1] . "<script"}eg;
  895.                                                         
  896.         $$stringR =~ s/<!doctype.*?>//i;  # some of the stricter doctypes reject my JavaScript
  897.                 
  898.         #utility::Log("Chunk processing exit: in script: " . $self->{"inScript"});
  899.         if ($headerPreviouslyInserted and $self->{"pendingJavaScript"})
  900.         {
  901.                 $$stringR = $self->AddJavaScript($$stringR);
  902.         }
  903. }
  904.  
  905. sub DoChunk
  906. {
  907.         my($self, $string, $from) = @_;
  908.         #print "DoChunk!!(" . (defined $self->{"unique"}) . ") $from: $string!!\n";
  909.                                                                 
  910.         if ($__unique)
  911.         {
  912.                 if (!defined $self->{"unique"} and $string =~ m/<\s*frameset/is)
  913.                 {
  914.                         $self->{"uniqueParent"} = unique_scripts::create($__listFormsFirst, $self->{"documentID"}, $self->{"target"});
  915.                 }
  916.                 if (defined $self->{"uniqueParent"})
  917.                 {
  918.                         $string =~ s/(<\s*frame\b.*?src\s*=\s*['"]?([^'"\s]+))/my $x=$self->{"uniqueParent"}; $$x->addFrame(web_site::makeAbsolute($2, $self->{"base"}, undef)), $1/egi;
  919.                 }
  920.         }
  921.                                         
  922.         if ($string =~ m{<\s*iframe}i)
  923.         {
  924.                 $self->{"safe"} = 0;
  925.         }
  926.                                                                                       
  927.                                                           
  928.         my @htmlComments = ();
  929.         my $generationIndex = 0;
  930.         if ($self->{"inComment"})
  931.         {
  932.                 if ($string =~ m/-->/)
  933.                 {
  934.                         $string =~ s{(^.*?-->)}{$htmlComments[$generationIndex] = $1, "<h__" . $generationIndex++ . "__c>"}egs;
  935.                         $self->{"inComment"} = 0;
  936.                 }
  937.         }
  938.                 
  939.         if (!$self->{"inComment"})
  940.         {
  941.                 $string =~ s{(<!--.*?-->)}{$htmlComments[$generationIndex] = $1, "<h__" . $generationIndex++ . "__c>"}egs;
  942.                 if ($string =~ m/<!--/)
  943.                 {
  944.                         $string =~ s{(<!--.*$)}{$htmlComments[$generationIndex] = $1, "<h__" . $generationIndex++ . "__c>"}egs;
  945.                         $self->{"inComment"} = 1;
  946.                 }
  947.                                                 
  948.                 my $formsDone = 0;
  949.                 if ($self->{"inForm"})
  950.                 {
  951.                         if ($string =~ s{(.*?)</form>}{$self->DecorateForm($1) . "</f__m>"}ise)
  952.                         {
  953.                                 $self->{"inForm"} = 0;
  954.                         }
  955.                         else
  956.                         {
  957.                                 $string = $self->DecorateForm($string);
  958.                                 $formsDone = 1;
  959.                         }
  960.                 }
  961.                 if (!$formsDone)
  962.                 {
  963.                         $string =~ s{<form\b(.*?)</form>}{"<f__m" . $self->DecorateForm($1) . "</f__m>"}gise;
  964.                         if ($string =~ s{<form\b(.*)}{"<f__m" . $self->DecorateForm($1)}ise)
  965.                         {
  966.                                 $self->{"inForm"} = 1;
  967.                         }
  968.                         else
  969.                         {
  970.                                 $self->{"inForm"} = 0;
  971.                         }
  972.                         
  973.                 }
  974.                 $string =~ s/\bf__m\b/form/gi;
  975.         }                        
  976.         $string =~ s{<h__(\d+)__c>}{$htmlComments[$1]}eg;
  977.         
  978.         $string = $self->DoLinks($string);
  979.         return $string;
  980. }
  981.                                                                                                                 
  982. sub GetPendingJavaScript
  983. {
  984.         my($self, $addScriptTags, $extra, $eof) = @_;
  985.         my $string = "";
  986.         $string .= "<script language=\"JavaScript\">\n" if $addScriptTags;
  987.         if ($eof or $self->{"pendingJavaScript"})
  988.         {
  989.                 $self->{"allJavaScript"} .= $self->{"pendingJavaScript"};
  990.                 if ($eof)
  991.                 {
  992.                         $string .= $self->{"allJavaScript"};
  993.                 }
  994.                 else
  995.                 {
  996.                         $string .= $self->{"pendingJavaScript"};
  997.                 } 
  998.                 $self->{"pendingJavaScript"} = "";
  999.         }
  1000.         $string .= "wk_data[0]=\"Web Keyboard $__version: " . $self->{"status"} . "\";\n";
  1001.         $string .= "wk_itemCount=" . $self->{"itemCount"} . ";\n";
  1002.         $string .= "$extra\n" if $extra;
  1003.         $string .= "</script>\n\n"  if $addScriptTags;
  1004.         return $string;
  1005. }
  1006.  
  1007. sub AddJavaScript
  1008. {
  1009.         my($self, $string) = @_;
  1010.         if ($self->{"hasScriptContent"})
  1011.         {
  1012.                 if (($string =~ s{</script>}{"</script>" . $self->GetPendingJavaScript(1, '', 0)}ei)
  1013.                 ||  ($string =~ s{<script\b}{$self->GetPendingJavaScript(1, '', 0) . "<script "}ei))
  1014.                 {
  1015.                         #print "$self: links cleared script\n";
  1016.                 }
  1017.         }
  1018.         elsif ($self->{"safe"})
  1019.         {
  1020.                 if ($string =~ s{</body>}{$self->GetPendingJavaScript(1, '', 0) . "</body>"}ei)
  1021.                 {
  1022.                         #print "$self: links cleared /html:$string\n";
  1023.                 }
  1024.                 elsif (($string =~ s{(</(a|select)>)}{"$1\n" . $self->GetPendingJavaScript(1, '', 0)}ei)
  1025.                 or  ($string =~ s{(<(a|input|select)\b)}{"\n" . $self->GetPendingJavaScript(1, '', 0)}ei)
  1026.                 )
  1027.                 {
  1028.                         #print "$self: links cleared select/input>\n";
  1029.                 }
  1030.         }
  1031.         return $string;
  1032. }
  1033.  
  1034.  
  1035. sub DecorateForm
  1036. {
  1037.         my($self, $form_text) = @_;
  1038.         utility::Log("---DecorateForm:$form_text");
  1039.         if (!$self->{"inForm"})
  1040.         {
  1041.                 # either we are processing the entire form, or this is the first chunk of this form
  1042.                 $self->{"fieldIndex"} = 0;
  1043.                 $self->{"formIndex"}++;
  1044.         }
  1045.                                         
  1046.         # next expression gives the correct behavior (for buttons with names like
  1047.         # ">> Next" but is too slow in some cases.
  1048.         #$form_text =~ s{(<\s*(input|select|textarea)\b([^'">]+|"[^"]*"|'[^']*')+>)}{$self->DecorateInputField($1)}egis;
  1049.         
  1050.         $form_text =~ s{(<\s*(input|select|textarea)\b[^>]+>)}{$self->DecorateInputField($1)}egis;
  1051.                         
  1052.         # DecorateInputField prepends a '<' to the finished text; thus input fields which lack
  1053.         # the extra '<' were not processed:
  1054.         if (!$self->{"slicedItem"} and $form_text =~ s/([^<])(<\s*[^>]*$)/$1/is)
  1055.         {
  1056.                 $self->{"slicedItem"} = $2;
  1057.                 utility::Log("post form: slice:" . $self->{"slicedItem"});
  1058.         }
  1059.         
  1060.         $form_text =~ s/<<\s*(input|select|textarea)/<$1/gi;
  1061.         return $form_text;
  1062.         
  1063. sub DecorateInputField
  1064. {
  1065.         my($self, $input) = @_;
  1066.                 
  1067.         # mark this input field as processed, to prevent it from being copied into slicedItem
  1068.         $input = "<" .  $input;  
  1069.         
  1070.         my $type = '';
  1071.         if ($input =~ /\btype\s*=\s*['"]?(\w+)/i)
  1072.         {
  1073.                 $type = $1;
  1074.         }
  1075.         my $name = '';
  1076.         if ($input =~ /\bname\s*=\s*['"]?([-\w_\.]+)/i)
  1077.         {
  1078.                 $name = $1;
  1079.         }
  1080.         $name = "\"$name\"";
  1081.         
  1082.         my $fieldIndex = $self->{"fieldIndex"}++;
  1083.         
  1084.         print "DecorateInputField($name($fieldIndex, $type))\n";
  1085.         
  1086.         my $elements = "wk_get_field($self->{'formIndex'},";
  1087.         if ($type =~ /^button$/i)
  1088.         {
  1089.                 return $input . $self->SuperScript(0, $elements . "$fieldIndex, $name).onclick()");
  1090.         }
  1091.         elsif ($type =~ /^hidden$/i)
  1092.         {
  1093.                 return $input;
  1094.         }
  1095.         elsif ($type =~ /^image/i)
  1096.         {
  1097.                 # this doesn't work.  For the case where the form contains a
  1098.                 # single input image, and is POSTed, the post data should contain
  1099.                 # "&imageInput.x=7imageInput.x=32" but does not with this method.
  1100.                 # 'next 20' image button on some search results yields this behavior
  1101.                 #return $input . $self->SuperScript(0, "document.forms[$self->{'formIndex'}].submit()");
  1102.                 $self->{"fieldIndex"}--;
  1103.                 return $input;
  1104.         }
  1105.         elsif ($type =~ /^(checkbox|radio|reset|submit)$/i)
  1106.         {
  1107.                 return $input unless $name or $type !~ /^radio$/i; # anonymous radio button setting crashes navigator
  1108.                 return $input . $self->SuperScript(0, $elements . "$fieldIndex, $name).click()");
  1109.         }
  1110.         return $self->SuperScript(0, $elements . "$fieldIndex, $name).focus()") . $input;
  1111. }
  1112.  
  1113. sub Page
  1114. {
  1115.         my($data, $target) = @_;
  1116.  
  1117.         my $d = Decorate->new($target, 200);
  1118.         $d->Chunk(\$data);
  1119.         return $data . $d->Cleanup();
  1120. }
  1121.  
  1122. #=====================================================================================
  1123. # methods below
  1124. use vars '@ISA';
  1125. require adynware::s_user;
  1126. @ISA = qw(s_user);
  1127.  
  1128. sub DocumentStart
  1129. {
  1130.         my($self) = @_;
  1131.         return "";
  1132. }
  1133.  
  1134. sub DocumentFinish
  1135. {
  1136.         my($self) = @_;
  1137.         return $self->Cleanup();
  1138. }
  1139.  
  1140. sub DocumentChunk
  1141. {
  1142.         my($self, $chunk) = @_;
  1143.         my $s = $self->Chunk($chunk);
  1144.         #print     "\n===================================================================\n";
  1145.         #print $s, "\n===================================================================\n";
  1146.         return $s;
  1147. }
  1148.  
  1149. sub Redirect
  1150. {
  1151.         my($self, $oldURL, $newURL) = @_;
  1152.         unique_scripts::redirect($oldURL, $newURL);
  1153. }
  1154.  
  1155. sub new
  1156. {
  1157.         my $this = shift;
  1158.         my $target = shift;
  1159.         my $status = shift;
  1160.         die "target is a required argument for decorate object" unless defined $target;
  1161.         my $class = ref($this) || $this;
  1162.         my $self = {};
  1163.         
  1164.         bless $self, $class;
  1165.         $self->Init($target, $status);
  1166.         return $self;
  1167. }
  1168.  
  1169. 1;
  1170.